# encoding: utf-8
import os
import sys
import cgi
import wsgiref.handlers
from wsgiref.handlers import CGIHandler

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from mimetypes import types_map
import models
import functions
import cache
import options
import urllib
import datetime
from models import taggable
import webstart as webstart
import codecs
import theme
import logging
from models import filesystem
from google.appengine.ext.webapp.util import run_wsgi_app
import appengine_admin
#from templatetags.filter import *
options = functions.get_options()
class BaseRequestHandler(webapp.RequestHandler):
    """Supplies a common template generation function.

    When you call generate(), we augment the template variables supplied with
    the current user in the 'user' variable and the current webapp request
    in the 'request' variable.
    """
    def initialize(self, request, response):
        global options
        webapp.RequestHandler.initialize(self, request, response)
        self.theme = theme.Theme(options.theme);
        
    def generate(self, template_name, template_values={}, page_path=None, type="main", parent=None,content_type='text/html',keyword=None,error=None):
        global options
        webapp.template.register_template_library('templatetags.filter')
        self.user = users.get_current_user()
        values = {
            'request': self.request,
            'user': users.GetCurrentUser(),
            'login_url': users.CreateLoginURL(self.request.uri),
            'logout_url': users.CreateLogoutURL('http://' + self.request.host + '/'),
#            'sidebar': functions.get_sidebar(),
            'categories': functions.w_categories(),
            'widgets': functions.w_sidebar(),
            'blog_link': 'http://' + self.request.host + '/',
            'options': options,
            'theme' : self.theme,
            'keyword':keyword,
            'error':error
            }
        values.update(template_values)
        directory = os.path.dirname(__file__)
        path = os.path.join(directory, os.path.join('templates', template_name))
#        path = theme.Theme(options.theme);
        html = template.render(path, values, debug=options.DEBUG)
        # Make cache
        if cache and options.CACHE and not self.user and page_path:
            cache.create_cache_page(parent, page_path, html, type , content_type)
        self.response.headers["Content-Type"] = "text/html"
        self.response.out.write(html)

    def main(self, message=u'没有这个页面'):
        values = {'content': '<h3>'+message+'</h3>'}
        self.generate(self.theme.main, values)

    def page(self,message=u'没有这个页面'):
        values = {'content': '<h3>'+message+'</h3>'}
        self.generate(self.theme.__getattr__("post"), values)
        
    def generate_js(self, html):
        self.response.headers["Content-Type"] = "text/html"
        self.response.out.write('<script language="JavaScript">'+ html + '</script>')


class NotFound(BaseRequestHandler):
    """Not Found page"""
    def get(self, error):
        self.main()        


class FeedHandler(BaseRequestHandler):
    """Feed"""
    def get(self):
        global options
        query = models.Post.all().order('-published').filter('draft',False).filter('post_type','post')
        posts = query.fetch(limit=options.posts_per_feed)
        values = { 'feed_date': posts[0].created,
                   'posts': posts }
        self.generate(self.theme.feed, values, os.environ['PATH_INFO'], 'feed', None,'text/xml')

class Download(BaseRequestHandler):
    def get(self, myfile):
        file=None
        path = self.request.path
        if path.startswith("/upload"):
            path = path[len('/upload'):]
        elif path.startswith("/file"):
            path = path[len('/file'):] 
        path =unicode(urllib.unquote_plus(path),'utf-8')
        if not path:
            self.main('没有找到这个文件！')
            return
#        cached_page = models.CachedPage.get_by_key_name(path)
        split = path.rfind('.')  
        ext = path[split + 1:]
        filenew = filesystem.Files.get_by_key_name(path)
        if not filenew:
            self.main('没有找到这个文件！')
            return
        else:
            ext = '.' + ext
            mimetype = 'application/octet-stream'
            if types_map.has_key(ext):
                mimetype = types_map[ext]
            self.response.headers['Content-Type'] = mimetype
            self.response.headers['Content-Disposition'] = 'inline; filename="' + filenew.basename.encode('utf-8') + '"'
            self.response.out.write(filenew.content)

class MainPageHandler(BaseRequestHandler):
    """Main page"""
    def get(self,offset=1):  
#        import util
#        util.utilData().w_widget("abc")
        if int(offset) >4000:
            self.main('页面不存在啦')
            return
        global options
        query = models.Post.all().order('-published').filter('draft',False).filter('post_type','post')
        #Pagination
        total_count = query.count()
        navigation = functions.navigation(offset, total_count, options.posts_per_page)
        of = (navigation['current']-1)*options.posts_per_page
        #Retrieve the posts
        posts = query.fetch(limit=options.posts_per_page,offset=of)
        values = {
              'posts': posts,
              'navigation': navigation
        }
        self.generate(self.theme.main, values, os.environ['PATH_INFO'],keyword="main")


class CategoryPageHandler(BaseRequestHandler):
    """Category page"""
    def get(self, category=None, offset=1):
        if int(offset) >4000:
            self.main(u'页面不存在啦')
            return
        if not category:
            self.main(u'这有这个分类')
            return
        #check if exist
        query=models.Category.all().filter('category_url',unicode(urllib.unquote_plus(category.strip("/")),'utf-8'))
        cat=query.get()
        if not cat:
            self.main(u'这有这个分类')
            return
        #get the posts of the category
        posts_query = models.Post.all().filter('categories_keys',cat).filter('draft',False).order('-published').filter('post_type','post')
        #Pagination
        total_count = posts_query.count()        
        limit = options.posts_per_page
        navigation = functions.navigation(offset, total_count, limit)
        of=(navigation['current']-1)*limit
        #Retrieve the posts
        posts = posts_query.fetch(limit=limit,offset=of)
        values = {
              'content':'<h3>Posts in category '+cat.category_name+'</h3>',
              'posts': posts,
              'navigation': navigation
        }
        self.generate(self.theme.category, values, os.environ['PATH_INFO'], "category", cat,keyword=cat.category_url) 

class TagPageHandler(BaseRequestHandler):
    """Category page"""
    def get(self, tagk=None, offset=1):
        if int(offset) >4000:
            self.main(u'页面不存在啦')
            return
        tagk=unicode(urllib.unquote_plus(tagk.strip("/")),'utf-8')
        if not tagk:
            self.main(u'标签不存在')
            return
        #check if exist
        tag=taggable.Tag.Get_By_Tag_Value(tagk)
        posts=[]
        if tag:
            for x in tag.tagged:
                post=models.Post.get(x)
                if post and not post.draft and post.post_type =='post':
                   posts.append(post)
#        posts=[ ss.strip() for ss in posts if not ss.draft and ss.post_type='post']
#        posts_query=models.Post.all().filter('tag_string',tag).filter('draft',False).order('-published').filter('post_type','post')
        #get the posts of the category
        def sort_by_published(post_a, post_b):
            comp = 0 # Assume equality
            if post_a.published > post_b.published:
                comp = -1
            elif post_a.published< post_b.published:
                comp = 1
            return comp
        posts.sort(sort_by_published)
        total_count = len(posts)       
        limit = options.posts_per_page
        navigation = functions.navigation(offset, total_count, limit)
        of=(navigation['current']-1)*limit
        #Retrieve the posts
        posts = posts[of:of+limit]
        values = {
              'content':'<h3>Posts in Tag '+tagk+'</h3>',
              'posts': posts,
              'navigation': navigation
        }
        self.generate(self.theme.tag, values, os.environ['PATH_INFO'], "tags", tag,keyword=tagk) 

class Archive(BaseRequestHandler):
    def get(self,yearmonth,offset=1):
        if int(offset) >4000:
            self.main(u'页面不存在啦')
            return
        try:
            year=int(yearmonth[:4])
            month=int(yearmonth[5:7])
            if 1982 > year or month >13 or month < 1:
                raise AttributeError
        except Exception, e:
            self.main(u'没有这个归档')
            return
        fromDay=datetime.datetime(year,month,1)
        month+=1
        if month==13:
            year+=1
            month=1
        toDay=datetime.datetime(year,month,1)
        posts_query=db.GqlQuery('select * from Post where modified >= :1 and modified<:2 and draft =:3 and post_type =:4 ORDER BY modified DESC',fromDay,toDay,False,'post')
#        posts_query = models.Post.all().filter('modified >=',fromDay).filter('modified<',toDay).filter('draft',False).filter('post_type','post')
        total_count = posts_query.count()        
        limit = options.posts_per_page
        navigation = functions.navigation(offset, total_count, limit)
        of=(navigation['current']-1)*limit
        #Retrieve the posts
        posts = posts_query.fetch(limit=limit,offset=of)
        values = {
              'content':'<h3>Posts in archive '+yearmonth+'</h3>',
              'posts': posts,
              'navigation': navigation
        }
        self.generate(self.theme.archive, values, os.environ['PATH_INFO'], "Archive", yearmonth,keyword=yearmonth) 

class PostPageHandler(BaseRequestHandler):
    """Post page"""
    def get(self, type ,permalink=None ,error=None):
        def do_relatedpost(pst):
            def sort_by_published(post_a, post_b):
                comp = 0 # Assume equality
                if post_a.get("published") > post_b.get("published"):
                    comp = -1
                elif post_a.get("published")< post_b.get("published"):
                    comp = 1
                return comp
            tags = pst.get_tags()
#            tags=taggable.Tag.Get_By_Tag_Value(tagk)
            if tags:
                posts=[]
                for tag in tags:
                    for x in tag.tagged:
                        post=models.Post.get(x)
                        if post and not post.draft and post.post_type =='post':
                           temp={'title':post.title,'permalink':post.permalink,'published':post.published}
                           if posts.count(temp)==0:
                               posts.append(temp)
                temp={'title':pst.title,'permalink':pst.permalink,'published':pst.published}
                if posts.count(temp)>0:
                    posts.remove(temp)
                posts.sort(sort_by_published)
                return posts[:5]
            return
        if not permalink:
            self.main(u'没有发现这个文章')
            return
        #check if exist
#        print unicode(permalink.strip("/"))
        import urllib
        query=models.Post.all().filter('permalink',unicode(urllib.unquote_plus(permalink.strip("/").split(".")[0]),"utf-8"))
        post=query.get()
        if not post:
            self.main('Post ' +  permalink +' not found')
            return
        values = {
              'post': post,
              'key': post.key(),
              'comments': post.comments.fetch(100),
              'form': models.CommentForm()
        }
        if post.post_type =='post':
            values.update({'relatedpost':do_relatedpost(post)})
        self.generate( self.theme.__getattr__(post.post_type), values, os.environ['PATH_INFO'], "post", post,error)

class NewCommentHandler(BaseRequestHandler):    
    """Create a new comment"""
    def post(self):
        post_key = self.request.get('post_key')
        #retriveve the data of the form
        data = models.CommentForm(data=self.request.POST)
        msg=''
        if not data.is_valid():
            for key in data.errors.keys():
                msg=msg+ "Growl.Error({title:'%s', text: '%s'});" % (key, data.errors[key])
        elif not post_key:
            msg = "Growl.Error({title:'Error', text: 'Invalid data'});" 
        else: #all fields filled
            try:
                post = models.Post.get(db.Key(post_key))
            except db.Error:
                msg = "Growl.Error({title:'Error', text: 'Invalid data'});" 
            if not post: #inavild key
                msg = "Growl.Error({title:'Error', text: 'Invalid data'});" 
            else:
                new_coment = data.save(commit=False)
                new_coment.post = post
                new_coment.ip = self.request.remote_addr
                try:
                    new_coment.put()                      
                except db.Error:
                   msg = "Growl.Error({title:'Error', text: 'Error saving data'});"              
        if msg:
            self.generate_js(msg)
        else:
            path =u'''post/'''+new_coment.post.permalink
            cache.delete_one_cache(path)
            self.generate_js('window.location.reload();')

class TNewCommentHandler(PostPageHandler):    
    """Create a new comment"""
    def post(self):
        post_key, author,email, link, text = (self.request.get(item) for item in ('post_key', 
                                                                                     'authorName',
                                                                                     'authorMail',
                                                                                     'authorSite',
                                                                                     'content'))

#        post_key = self.request.get('post_key')
        #retriveve the data of the form
        post=''
        msg=''
        if not author:
            msg="输入姓名"
        elif not email:
            msg = "输入联系邮件" 
        elif not text:
            msg = "输入正文"
        else: #all fields filled
            try:
                post = models.Post.get(db.Key(post_key))
            except db.Error:
                msg = "请不要黑我啊！" 
            if not post: #inavild key
                msg = "请不要黑我啊！" 
            else:
                new_coment = models.Comment(author=author,email=email,text=text)
                if link:
                    try:
                        new_coment.link = link
                    except:
                        msg = "输入正确的URL!"
                    else:
                        new_coment.post = post
                        new_coment.ip = self.request.remote_addr
                        try:
                            new_coment.put()                      
                        except db.Error:
                           msg = "请不要黑我啊！" 
                else:
                        new_coment.post = post
                        new_coment.ip = self.request.remote_addr
                        try:
                            new_coment.put()                      
                        except db.Error:
                           msg = "请不要黑我啊！"              
        if msg:
            self.page(msg)
        else:
            path =u'''post/'''+new_coment.post.permalink
            cache.delete_one_cache(path)
            self.redirect('/post/'+(post.permalink).encode('utf-8', 'ignore'),"post")
            
class Import(BaseRequestHandler):
    def post(self):
        albumName = self.request.get('albumName')
        albumUrl = self.request.get('albumUrl')
        artist = self.request.get('artist')
        songName = self.request.get('songName')
        songUrl = self.request.get('songUrl')
        sourcesite = self.request.get('sourcesite')
        content = self.request.get('content')
        lrc=models.Lrc.gql("where songUrl = :1",songUrl)
        if lrc.count()==0:
            models.Lrc(albumName =albumName,albumUrl =albumUrl,
                              artist =artist,songName =songName,
                              songUrl =songUrl,sourcesite =sourcesite,
                              content =content).put()
        lrc=models.Lrc.gql("where songUrl = :1",songUrl).fetch(1)[0]
        self.response.out.write(lrc.content)

class ImportB(BaseRequestHandler):
    def post(self):
        data = self.request.get('upfile').split("B$Q")
        str=''
        for ones in data:
            if len(ones)!=0:
                one=eval(ones)
                lrc=models.Lrc.gql("where songUrl = :1",one['songUrl'])
                if lrc.count()==0:
                    models.Lrc(albumName =one['albumName'],albumUrl =one['albumUrl'],
                                      artist =one['artist'],songName =one['songName'],
                                      songUrl =one['songUrl'],sourcesite =one['sourcesite'],
                                      content =unicode(one['content'])).put()
                lrc=models.Lrc.gql("where songUrl = :1",one['songUrl']).fetch(1)[0]
                str+=(lrc.content)
        self.response.out.write(str)

#class SiteXml(BaseRequestHandler):
#    def get(self):
#        str =u'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
#                <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN" xml:lang="zh-CN">
#                <head><meta http-equiv=Content-Type content="text/html;charset=utf-8"></head><body>'''
#        baseUrl='http://' + self.request.host + '/'
#        
#        posts = models.Post.all();
#        for post in posts:
#            url = baseUrl+ "post/"+post.permalink
#            str = str +'''<a href="''' + url +'''">'''+ url +'''</a><br/>\n'''
#        str=str+"<br/>\n" 
#        
#        cats = models.Category.all().order('category_name');
#        for cat in cats:
#            url = baseUrl+"category/"+cat.category_url
#            str = str +'''<a href="''' + url +'''">'''+ url +'''</a><br/>\n'''
#        str=str+"<br/>\n"   
#        
#        tags = taggable.Tag.Get_Tags_By_Frequency();
#        for tag in tags:
#            if len(tag.tagged) > 0:
#                url = baseUrl+"tag/"+tag.tag
#                str = str +'''<a href="''' + url +'''">'''+ url +'''</a><br/>\n'''
#        str=str+"<br/>\n"
#        
#        arcs = models.Archive.all().order('yearmonth')
#        for arc in arcs:
#            url = baseUrl+"archive/"+arc.yearmonth+"\n"
#            str = str +'''<a href="''' + url +'''">'''+ url +'''</a><br/>\n'''
#        
#        str =str+'''</body>
#            </html>'''
#        self.response.headers["Content-Type"] = "text/html"
#        self.response.out.write(str)
                
class GetFile(webapp.RequestHandler):
    def get(self):
        cwd = os.getcwd()
        theme_path = os.path.join(cwd, 'themes')
        max_age = 600  #expires in 10 minutes

        request_path = self.request.path[len('/themes/'):]
        server_path = os.path.normpath(os.path.join(cwd, 'themes', request_path))
        
        last_config_time =True
        try:
            opts = memcache.get("options")
        except:
            opts = None
        if opts is not None:
            last_config_time =False
        if self.request.if_modified_since and last_config_time:
            self.response.headers['Date'] = functions.format_date(datetime.datetime.utcnow())
            self.response.headers['Last-Modified'] = functions.format_date(datetime.datetime.utcnow())
            self.response.set_status(304)
            self.response.clear()

        elif server_path.startswith(theme_path):
            ext = os.path.splitext(server_path)[1]
            if types_map.has_key(ext):
                mime_type = types_map[ext]
            else:
                mime_type = 'application/octet-stream'
            try:
                self.response.headers['Content-Type'] = mime_type
                self.response.headers['Last-Modified'] = functions.format_date(datetime.datetime.utcnow())
                self.response.out.write(open(server_path, 'rb').read())
            except Exception, e:
                logging.info(e)
                self.response.set_status(404)
        else:
            self.response.set_status(404)
      
def Main():
    """Main method, decides to either serve cached content or call the handler."""
    #Check if requested page is cached
    users.level = 0
    if users.get_current_user():
        users.level = 3
        if users.is_current_user_admin() or options.permission.count(users.get_current_user().email()) > 0:
            users.level = 6
            if users.is_current_user_admin():
                users.level = 9
    if users.level == 0 and options.CACHE and cache.get_cache_page(os.environ['PATH_INFO'].strip("/")): #Don't send cache pages to logged users
        return
    application = webstart.WSGIApplication2([(r'/feed', FeedHandler),
#                                          (r'/sitemap/*$', SiteXml),
                                          (r'/category/(.*)/(\d+)/$', CategoryPageHandler),
                                          (r'/category/(.*)/(\d+)$', CategoryPageHandler),
                                          (r'/category/(.*)', CategoryPageHandler),
                                          (r'/tag/(.*)/(\d+)/$', TagPageHandler),
                                          (r'/tag/(.*)/(\d+)$', TagPageHandler),
                                          (r'/tag/(.*)', TagPageHandler),
                                          (r'/archive/(.*)/(\d+)/$', Archive),
                                          (r'/archive/(.*)/(\d+)$', Archive),
                                          (r'/archive/(.*)', Archive),
                                          (r'/(post|page)/(.*)$', PostPageHandler),
                                          ('/comment', NewCommentHandler),
                                          ('/newcomment', TNewCommentHandler),
                                          ('/upload/(.*)', Download),
                                          ('/file/(.*)', Download),
                                          ('/themes/[\\w\\-]+/templates/.*', NotFound),
                                          ('/themes/[\\w\\-]+/.+', GetFile),
                                          ('/import/', Import),
                                          ('/importb/', ImportB),
                                          (r'/(\d+)$', MainPageHandler),
                                          (r'/(\d+)/$', MainPageHandler),
                                          ('/', MainPageHandler),
                                          ('/(.*)',NotFound)], debug=options.DEBUG)
    wsgiref.handlers.CGIHandler().run(application)
    return
    

if __name__ == "__main__":
  Main()